package com.heima.wemedia.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.heima.apis.article.IArticleClient;
import com.heima.common.exception.CustomException;
import com.heima.common.tess4j.Tess4jClient;
import com.heima.file.service.FileStorageService;
import com.heima.model.article.dtos.ArticleDto;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.wemedia.pojos.WmChannel;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.model.wemedia.pojos.WmSensitive;
import com.heima.model.wemedia.pojos.WmUser;
import com.heima.utils.common.SensitiveWordUtil;
import com.heima.wemedia.mapper.WmChannelMapper;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.mapper.WmSensitiveMapper;
import com.heima.wemedia.mapper.WmUserMapper;
import com.heima.wemedia.service.WmNewsAutoScanService;
import lombok.extern.slf4j.Slf4j;
import net.sourceforge.tess4j.TesseractException;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
@Transactional
public class WmNewsAutoScanServiceImpl implements WmNewsAutoScanService {

    @Autowired
    private WmNewsMapper wmNewsMapper;

    @Autowired
    private IArticleClient iArticleClient;

    @Autowired
    private WmChannelMapper wmChannelMapper;

    @Autowired
    private WmUserMapper wmUserMapper;

    @Autowired
    private WmSensitiveMapper wmSensitiveMapper;

    @Autowired
    private FileStorageService fileStorageService;

    @Autowired
    private Tess4jClient tess4jClient;

    @Async
    @Override
    public void autoScanWmNews(Integer id) {
        //int a = 1/0;

        //1.1校验是否存在文章
        WmNews wmNew = wmNewsMapper.selectById(id);
        if (wmNew == null) {
            throw new CustomException(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        //1.2校验状态是否为待审核
        if (wmNew.getStatus() == WmNews.Status.SUBMIT.getCode()){
            //2.获取文章图文信息
            Map<String,Object> textAndImages = handleTextAndImages(wmNew);
            //3.1审核文本内容 阿里云 TODO
            boolean isTextScan = handleTextScan((String)textAndImages.get("text"),wmNew);
            if (!isTextScan){return;}
            //3.2审核图片内容 阿里云 TODO
            boolean isImageScan = handleImageScan((List<String>)textAndImages.get("images"),wmNew);
            if(!isImageScan){return;}
            //3.3审核通过，修改自媒体文章状态
            updateWmNews(wmNew,WmNews.Status.SUCCESS.getCode(),"文章内容审核通过，待发布");

            //4.1保存app相关文章
            ResponseResult responseResult = saveAppArticle(wmNew);
            if (responseResult.getCode() != 200){
                throw new CustomException(AppHttpCodeEnum.PROCESS_SAVEAPARTICLE_FAIL);
            }
            //4.2保存app端文章成功，设置articleID
            wmNew.setArticleId((Long) responseResult.getData());
            //4.3设置自媒体文章布时间
            //wmNew.setPublishTime(new Date());
            //4.4修改自媒体文章状态
            updateWmNews(wmNew,WmNews.Status.PUBLISHED.getCode(),"文章已发布(自动审核)");
        } else if (wmNew.getStatus() == WmNews.Status.ADMIN_SUCCESS.getCode()){  // 人工审核通过
            ResponseResult responseResult = saveAppArticle(wmNew);
            if (responseResult.getCode() != 200){
                throw new CustomException(AppHttpCodeEnum.PROCESS_SAVEAPARTICLE_FAIL);
            }
            wmNew.setArticleId((Long) responseResult.getData());
            updateWmNews(wmNew,WmNews.Status.PUBLISHED.getCode(),"文章已发布(人工审核)");
        }

    }

    /**
     * 自管理敏感词过滤
     * @param text
     * @param wmNew
     * @return
     */
    private boolean handleSensitiveScan(String text, WmNews wmNew) {
        //结果标识
        boolean flag = true;
        //获取所有的敏感词
        List<WmSensitive> wmSensitives = wmSensitiveMapper.selectList(Wrappers.<WmSensitive>lambdaQuery().select(WmSensitive::getSensitives));
        List<String> senstiveList = wmSensitives.stream().map(WmSensitive::getSensitives).collect(Collectors.toList());

        //初始化敏感词库
        SensitiveWordUtil.initMap(senstiveList);
        //查看文章中是否包含敏感词
        Map<String, Integer> map = SensitiveWordUtil.matchWords(text);
        if (!map.isEmpty()){
            flag = false;
            return flag;
        }

        return flag;
    }

    /**
     * 保存app端相关的文章数据
     * @param wmNews
     */
    private ResponseResult saveAppArticle(WmNews wmNews){
        ArticleDto articleDto = new ArticleDto();
        //拷贝属性到articleDto中
        BeanUtils.copyProperties(wmNews,articleDto);
        //设置布局
        articleDto.setLayout(wmNews.getType());
        //设置频道
        WmChannel wmChannel = wmChannelMapper.selectById(wmNews.getChannelId());
        if (wmChannel != null) {
            articleDto.setChannelName(wmChannel.getName());
        }
        //设置作者
        articleDto.setAuthorId(wmNews.getUserId().longValue());
        WmUser wmUser = wmUserMapper.selectById(wmNews.getUserId());
        if (wmUser != null){
            articleDto.setAuthorName(wmUser.getName());
        }
        //设置ID
        if (wmNews.getArticleId() != null) {
            articleDto.setId(wmNews.getArticleId());
        }
        //设置创建时间
        articleDto.setCreatedTime(new Date());
        //设置发布时间
        if (wmNews.getPublishTime() == null){
            articleDto.setPublishTime(new Date());
        }

        ResponseResult responseResult = iArticleClient.saveArticle(articleDto);
        return responseResult;
    }

    /**
     * 审核图片
     * @param imageList
     * @param wmNews
     * @return
     */
    private boolean handleImageScan(List<String> imageList,WmNews wmNews){
        boolean flag = true;
        //没有图片则直接审核通过
        if (imageList.size() <= 0 || imageList == null){
            return flag;
        }
        //图片去重
        List<String> imgList = imageList.stream().distinct().collect(Collectors.toList());
        List<byte[]> images = new ArrayList<>();
              //从minio中下载图片
              for (String url : imgList) {
                  byte[] bytes = fileStorageService.downLoadFile(url);

                  ByteArrayInputStream in = new ByteArrayInputStream(bytes);
                  BufferedImage bufferedImage = null;
                  try {
                      bufferedImage = ImageIO.read(in);
                  } catch (IOException e) {
                      e.printStackTrace();
                  }
                  //图片识别
                  String result = null;
                  try {
                      result = tess4jClient.doOCR(bufferedImage);
                  } catch (TesseractException e) {
                      e.printStackTrace();
                  }
                  //审核图片中的文本信息
                  boolean isTextScan = handleTextScan(result, wmNews);
                  if (!isTextScan){
                      //审核不通过，修改自媒体文章状态
                      updateWmNews(wmNews,WmNews.Status.FAIL.getCode(),"审核失败，文章图片中含有违规文本");
                      return isTextScan;
                  }
                  //文本信息审核通过则可以准备进行阿里云图片审核
                  images.add(bytes);
              }
                //阿里云图片审核 TODO

        return flag;
    }

    /**
     * 审核文本
     * @param text
     * @param wmNew
     * @return
     */
    private boolean handleTextScan(String text, WmNews wmNew) {
        boolean flag = true;
        //没有文本直接审核通过
        if (StringUtils.isBlank(text)){
            return flag;
        }
        //自管理敏感词过滤
        boolean isSensitiveScan = handleSensitiveScan(text, wmNew);
        if (!isSensitiveScan){
            //审核不通过，修改自媒体文章状态
            updateWmNews(wmNew,WmNews.Status.FAIL.getCode(),"审核失败，文章文本中含有违规信息");
            return isSensitiveScan;
        }

        //阿里云文本审核 TODO
        return flag;
    }

    /**
     * 修改自媒体文章内容
     * @param wmNews
     * @param status
     * @param reason
     */
    private void updateWmNews(WmNews wmNews, short status, String reason) {
        wmNews.setStatus(status);
        wmNews.setReason(reason);
        wmNewsMapper.updateById(wmNews);
    }

    /**
     * 提取自媒体文章图文信息
     * @param wmNew
     * @return
     */
    private Map<String, Object> handleTextAndImages(WmNews wmNew) {
        //存储文本内容
        StringBuilder stringBuilder = new StringBuilder();
        //存储图片内容
        List<String> imageList = new ArrayList<>();
        //最终结果集
        Map<String,Object> result = new HashMap<>();

        if (StringUtils.isNotBlank(wmNew.getContent())){
            List<Map> maps = JSONArray.parseArray(wmNew.getContent(),Map.class);
            for (Map map : maps) {
                if (map.get("type").equals("text")){
                    stringBuilder.append(map.get("value"));
                }
                if (map.get("type").equals("image")){
                    imageList.add((String)map.get("value"));
                }
            }
        }

        //提取文章封面图片
        if (StringUtils.isNotBlank(wmNew.getImages())){
            List<String> images = Arrays.asList(wmNew.getImages());
            imageList.addAll(images);
        }
        result.put("text",stringBuilder.toString());
        result.put("images",imageList);

        return result;
    }
}
